#!/usr/bin/python
__author__ = 'codefish'

from mininet.net import Mininet
from mininet.node import Node
from mininet.link import Link, Intf
from mininet.log import setLogLevel, info
from mininet.util import quietRun, pmonitor

from time import sleep
import httplib
import json

def simpleTree( cname='controller', cargs='-v ptcp:' ):
    info( "*** Creating nodes\n" )
    controller = Node( 'c0', inNamespace=False )
    s0 = Node( 's0', inNamespace=False )
    h0 = Node( 'h0' )
    h1 = Node( 'h1' )
    Link( h0, s0 )
    Link( h1, s0 )

    h0.setIP( '192.168.123.1/24' )
    h1.setIP( '192.168.123.2/24' )

    info( "*** Starting network using Open vSwitch\n" )
    controller.cmd( cname + ' ' + cargs + '&' )
    s0.cmd( 'ovs-vsctl del-br s0-br0' )
    s0.cmd( 'ovs-vsctl add-br s0-br0' )

    bondCmdSuf = "bond_mode=balance-slb bond_updelay=31000 fake_bridge=false lacp=off bond_downdelay=200 bond_fake_iface=true"
    bondCmd = "ovs-vsctl add-bond s0-br0 bond0 "
    for intf in s0.intfs.values():
        bondCmd += str(intf)
        bondCmd += ' '
    bondCmd += bondCmdSuf
    info( "\n***** CMD for s0 = " + bondCmd )
    s0.cmd(bondCmd)
    info("\n")

    info( "====== Show bond0 =====\n" )
    info( s0.cmd("ovs-appctl bond/show bond0") )
    info("\n")

    # Start running test
    info( "*** Running test\n" )
    h0.cmdPrint( 'ping -c1 ' + h1.IP() )

    # Tear down
    info( "*** Stopping network\n" )
    controller.cmd( 'kill %' + cname )
    s0.cmd( 'ovs-vsctl del-br s0-br0' )
    s0.deleteIntfs()
    info( '\n' )

def testBond(cname='controller', cargs='-v ptcp:'):
   info("testing nodes\n")
   controller = Node( 'c0', inNamespace=False )

   h0 = Node( 'h0' )
   h1 = Node( 'h1' )
   h2 = Node( 'h2' )
   h3 = Node( 'h3' )
   s0 = Node( 's0', inNamespace=False )
   s1 = Node( 's1', inNamespace=False )
   Link( h0, s0 )
   Link( h1, s0 )
   Link( s0, s1 )
   Link( s0, s1 )

   s0.cmd("ovs-vsctl add-br s0-br0")

   info("===s0 ifconfig===\n" + s0.cmd("ifconfig")+"\n")
   info("===s1 ifconfig===\n" + s1.cmd("ifconfig")+"\n")
   info("===s0 show br===\n" + s0.cmd("ovs-vsctl list-br")+"\n")
   info ( s0.cmd("ovs-vsctl add-bond s0-br0 bond0 s0-eth2 s0-eth3 bond_mode=balance-slb bond_updelay=31000 fake_bridge=false lacp=off  bond_downdelay=200 bond_fake_iface=true") + "\n")
   sleep(1)
   info( s0.cmd("ovs-appctl bond/show bond0")  + "\n")

   info( s0.cmd("ovs-vsctl add-port s0-br0 s0-eth0") )
   info( s0.cmd("ovs-vsctl add-port s0-br0 s0-eth1") )
   info( "===s0 show br===\n" + s0.cmd("ovs-vsctl list-ifaces s0-br0")  + "\n")

   # ========================================================= #

   Link( h2, s1 )
   Link( h3, s1 )

   h0.setIP( '192.168.123.1/24' )
   h1.setIP( '192.168.123.2/24' )
   h2.setIP( '192.168.123.3/24' )
   h3.setIP( '192.168.123.4/24' )

   s1.cmd("ovs-vsctl add-br s1-br0")
   info( s1.cmd("ifconfig")+"\n" )
   info( s1.cmd("ovs-vsctl add-port s1-br0 s1-eth0") )
   info( s1.cmd("ovs-vsctl add-port s1-br0 s1-eth1") )
   info( s1.cmd("ovs-vsctl add-port s1-br0 s1-eth2") )
   info( s1.cmd("ovs-vsctl add-port s1-br0 s1-eth3") )


   controller.cmd( cname + ' ' + cargs + '&' )
   s1.cmd( 'ovs-vsctl set-controller s1-br0 tcp:127.0.0.1:6600' )
   info( '*** Waiting for s1 to connect to controller' )
   while 'is_connected' not in quietRun( 'ovs-vsctl show' ):
       sleep( 1 )
       info( '.' )
   info( '\n' )

   info( "====testing====\n" )
   #h0.cmdPrint( 'ping -c1 ' + h1.IP() )
   h1.cmd( 'iperf -s &' )

   # pop = h2.popen( "ping " + h1.IP())
   # pmonitor()
   popens = {}
   popens[h2] = h2.popen( 'iperf -c ' + h1.IP())
   popens[h3] = h3.popen( 'iperf -c ' + h1.IP())
   timer = 0
   for h, line in pmonitor(popens):
       if h and len(line) > 0:
           print timer
           print line
           timer += 1

   # Tear down
   """
   info( "*** Stopping network\n" )
   controller.cmd( 'kill %' + cname )
   s0.cmd( 'ovs-vsctl del-br s0-br0' )
   s0.deleteIntfs()
   info( '\n' )
   """
   sleep(100)

def testBottleneck(cname='controller', cargs='-v ptcp:'):

    controller = Node( 'c0', inNamespace=False )
    h0 = Node( 'h0' )
    h1 = Node( 'h1' )
    h2 = Node( 'h2' )
    s0 = Node( 's0', inNamespace=False )
    Link(h0, s0)
    Link(h1, s0)
    Link(h2, s0)
    h0.setIP( '192.168.123.1/24' )
    h1.setIP( '192.168.123.2/24' )
    h2.setIP( '192.168.123.3/24' )

    s0.cmd( 'ovs-vsctl del-br br0' )
    s0.cmd( 'ovs-vsctl add-br br0' )

    for intf in s0.intfs.values():
        print s0.cmd( 'ovs-vsctl add-port br0 %s' % intf )

    controller.cmd( cname + ' ' + cargs + '&' )
    s0.cmd( 'ovs-vsctl set-controller br0 tcp:127.0.0.1:6633' )

    info( '*** Waiting for s0 to connect to controller' )
    while 'is_connected' not in quietRun( 'ovs-vsctl show' ):
        sleep( 1 )
        info( '.' )
    info( '\n' )

    info( "====iperfing====\n" )
    h0.cmd( 'iperf -s &' )
    popens = {}
    popens[h1] = h1.popen( 'iperf -c ' + h0.IP())
    popens[h2] = h2.popen( 'iperf -c ' + h0.IP())

    timer = 0
    for h, line in pmonitor(popens):
        if h and len(line) > 0:
            print timer
            print line
            timer += 1


def testArcher():
    # Hey dude! Do not change name anymore! Your name is Archer!
    pass

def testStaticPusher(cname='controller', cargs='-v ptcp:'):
    info("testing nodes\n")
    controller = Node( 'c0', inNamespace=False )

    h0 = Node( 'h0' )
    h1 = Node( 'h1' )
    h2 = Node( 'h2' )
    h3 = Node( 'h3' )
    s0 = Node( 's0', inNamespace=False )
    s1 = Node( 's1', inNamespace=False )
    Link( h0, s0 )
    Link( h1, s0 )
    Link( s0, s1 )
    Link( s0, s1 )

    s0.cmd("ovs-vsctl add-br s0-br0")

    info("===s0 ifconfig===\n" + s0.cmd("ifconfig")+"\n")
    info("===s1 ifconfig===\n" + s1.cmd("ifconfig")+"\n")
    info("===s0 show br===\n" + s0.cmd("ovs-vsctl list-br")+"\n")
    info ( s0.cmd("ovs-vsctl add-bond s0-br0 bond0 s0-eth2 s0-eth3 bond_mode=balance-slb bond_updelay=31000 fake_bridge=false lacp=off  bond_downdelay=200 bond_fake_iface=true") + "\n")
    sleep(1)
    info( s0.cmd("ovs-appctl bond/show bond0")  + "\n")

    info( s0.cmd("ovs-vsctl add-port s0-br0 s0-eth0") )
    info( s0.cmd("ovs-vsctl add-port s0-br0 s0-eth1") )
    info( "===s0 show br===\n" + s0.cmd("ovs-vsctl list-ifaces s0-br0")  + "\n")

    # ========================================================= #
    Link( h2, s1 )
    Link( h3, s1 )

    h0.setIP( '192.168.123.1/24' )
    h1.setIP( '192.168.123.2/24' )
    h2.setIP( '192.168.123.3/24' )
    h3.setIP( '192.168.123.4/24' )

    s1.cmd("ovs-vsctl add-br s1-br0")
    info( s1.cmd("ifconfig")+"\n" )
    info( s1.cmd("ovs-vsctl add-port s1-br0 s1-eth0") )
    info( s1.cmd("ovs-vsctl add-port s1-br0 s1-eth1") )
    info( s1.cmd("ovs-vsctl add-port s1-br0 s1-eth2") )
    info( s1.cmd("ovs-vsctl add-port s1-br0 s1-eth3") )

    controller.cmd( cname + ' ' + cargs + '&' )
    s1.cmd( 'ovs-vsctl set-controller s1-br0 tcp:127.0.0.1:6600' )
    info( '*** Waiting for s1 to connect to controller' )
    while 'is_connected' not in quietRun( 'ovs-vsctl show' ):
        sleep( 1 )
        info( '.' )
    info( '\n' )

    info( "====testing====\n" )
    #h0.cmdPrint( 'ping -c1 ' + h1.IP() )
    h1.cmd( 'iperf -s &' )

    var = raw_input("Start ping now?: y/n ")
    while(var != "y"):
        print var
        var = raw_input("Start ping now?: y/n ")

    popens = {}
    popens[h2] = h2.popen( 'ping ' + h1.IP())
    popens[h3] = h3.popen( 'ping ' + h1.IP())
    timer = 0
    for h, line in pmonitor(popens):
        if h and len(line) > 0:
            print timer
            print line
            timer += 1

if __name__ == '__main__':
    setLogLevel( 'info' )
    info( '***  Link aggregation\n' )
    Mininet.init()
    # simpleTree()
    # testBond()
    # testArcher()
    # testBottleneck()
    testStaticPusher()


